package org.merak.core.persistence.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;

public class XStatement implements Statement {

	//~ Attributes /////////////////////////////////////////////////////////////
	//**************************************************************************
	private XConnection conn = null;
	private Statement   stm  = null;

	//~ Constructors ///////////////////////////////////////////////////////////
	//**************************************************************************
	public XStatement(XConnection connection) throws SQLException {
		this.conn = connection;
	}

	//~ Methods ////////////////////////////////////////////////////////////////
	//**************************************************************************
	protected void renew() throws SQLException  {
		this.stm = this.conn.getWrappedConnection().createStatement();
	}
	//**************************************************************************
	protected Statement getStatement() throws SQLException {
		if (this.conn.isClosed() || this.stm==null) this.renew();
		return this.stm;
	}
	//**************************************************************************
	@Override
	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		return this.getStatement().isWrapperFor(arg0);
	}
	//**************************************************************************
	@Override
	public <T> T unwrap(Class<T> arg0) throws SQLException {
		return this.getStatement().unwrap(arg0);
	}
	//**************************************************************************
	@Override
	public void addBatch(String arg0) throws SQLException {
		this.getStatement().addBatch(arg0);
	}
	//**************************************************************************
	@Override
	public void cancel() throws SQLException {
		this.getStatement().cancel();
	}
	//**************************************************************************
	@Override
	public void clearBatch() throws SQLException {
		this.getStatement().clearBatch();
	}
	//**************************************************************************
	@Override
	public void clearWarnings() throws SQLException {
		this.getStatement().clearWarnings();
	}
	//**************************************************************************
	@Override
	public void close() throws SQLException {
		this.getStatement().close();
	}
	//**************************************************************************
	@Override
	public boolean execute(final String sql) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().execute(sql);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().execute(sql);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public boolean execute(final String arg0, final int arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().execute(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().execute(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public boolean execute(final String arg0, final int[] arg1) throws SQLException {

		try {
			// Try to execute normally
			return this.getStatement().execute(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().execute(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public boolean execute(final String arg0,final String[] arg1) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().execute(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().execute(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int[] executeBatch() throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeBatch();
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<int[]>() {
				@Override
				public int[] retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().executeBatch();
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public ResultSet executeQuery(final String sql) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeQuery(sql);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<ResultSet>() {
				@Override
				public ResultSet retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().executeQuery(sql);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0,final int arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0,arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().executeUpdate(arg0,arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0,final int[] arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().executeUpdate(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0,final String[] arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().executeUpdate(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XStatement.this.getStatement().executeUpdate(arg0);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public XConnection getConnection() throws SQLException {
		return this.conn;
	}
	//**************************************************************************
	@Override
	public int getFetchDirection() throws SQLException {
		return this.getStatement().getFetchDirection();
	}
	//**************************************************************************
	@Override
	public int getFetchSize() throws SQLException {
		return this.getStatement().getFetchSize();
	}
	//**************************************************************************
	@Override
	public ResultSet getGeneratedKeys() throws SQLException {
		return this.getStatement().getGeneratedKeys();
	}
	//**************************************************************************
	@Override
	public int getMaxFieldSize() throws SQLException {
		return this.getStatement().getMaxFieldSize();
	}
	//**************************************************************************
	@Override
	public int getMaxRows() throws SQLException {
		return this.getStatement().getMaxRows();
	}
	//**************************************************************************
	@Override
	public boolean getMoreResults() throws SQLException {
		return this.getStatement().getMoreResults();
	}
	//**************************************************************************
	@Override
	public boolean getMoreResults(int arg0) throws SQLException {
		return this.getStatement().getMoreResults(arg0);
	}
	//**************************************************************************
	@Override
	public int getQueryTimeout() throws SQLException {
		return this.getStatement().getQueryTimeout();
	}
	//**************************************************************************
	@Override
	public ResultSet getResultSet() throws SQLException {
		return this.getStatement().getResultSet();
	}
	//**************************************************************************
	@Override
	public int getResultSetConcurrency() throws SQLException {
		return this.getStatement().getResultSetConcurrency();
	}
	//**************************************************************************
	@Override
	public int getResultSetHoldability() throws SQLException {
		return this.getStatement().getResultSetHoldability();
	}
	//**************************************************************************
	@Override
	public int getResultSetType() throws SQLException {
		return this.getStatement().getResultSetType();
	}
	//**************************************************************************
	@Override
	public int getUpdateCount() throws SQLException {
		return this.getStatement().getUpdateCount();
	}
	//**************************************************************************
	@Override
	public SQLWarning getWarnings() throws SQLException {
		return this.getStatement().getWarnings();
	}
	//**************************************************************************
	@Override
	public boolean isClosed() throws SQLException {
		return this.getStatement().isClosed();
	}
	//**************************************************************************
	@Override
	public boolean isPoolable() throws SQLException {
		return this.getStatement().isPoolable();
	}
	//**************************************************************************
	@Override
	public void setCursorName(String arg0) throws SQLException {
		this.getStatement().setCursorName(arg0);
	}
	//**************************************************************************
	@Override
	public void setEscapeProcessing(boolean arg0) throws SQLException {
		this.getStatement().setEscapeProcessing(arg0);
	}
	//**************************************************************************
	@Override
	public void setFetchDirection(int arg0) throws SQLException {
		this.getStatement().setFetchDirection(arg0);
	}
	//**************************************************************************
	@Override
	public void setFetchSize(int arg0) throws SQLException {
		this.getStatement().setFetchSize(arg0);

	}
	//**************************************************************************
	@Override
	public void setMaxFieldSize(int arg0) throws SQLException {
		this.getStatement().setMaxFieldSize(arg0);
	}
	//**************************************************************************
	@Override
	public void setMaxRows(int arg0) throws SQLException {
		this.getStatement().setMaxRows(arg0);
	}
	//**************************************************************************
	@Override
	public void setPoolable(boolean arg0) throws SQLException {
		this.getStatement().setPoolable(arg0);
	}
	//**************************************************************************
	@Override
	public void setQueryTimeout(int arg0) throws SQLException {
		this.getStatement().setQueryTimeout(arg0);
	}
	//**************************************************************************

}
